﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Afru;
using Afru.Components.Messaging;

namespace Afru
{
    public class DestroyableSprite : Sprite
    {
        #region Variables

        Texture2D _damageSprite;
        string _damageSpritePath;
        Vector2 _damageSpriteOrigin;
        Texture2D _damageAlphaSprite;
        string _damageAlphaSpritePath;
        Vector2 _damageAlphaSpriteOrigin;
        Color[] _damageSpriteDataA,
            _damageSpriteDataB;

        bool _allowAlphaChange;
        bool _allowTextureChange;
        bool _hasDamageWaiting;
        List<Vector2> _pendingDamage;

        float _updateTime;
        float _updateCurrent;
                
        #endregion

        #region Constructor

        public DestroyableSprite(string TexturePath, string DamageTexturePath, string DamageAlphaTexturePath, Vector2 InitialPosition, float UpdateSeconds) : base(TexturePath, InitialPosition)
        {
            if ((DamageTexturePath == null) || (DamageTexturePath == ""))
            {
                _allowTextureChange = false;   
            }
            else
            {
                _damageSpritePath = DamageTexturePath;
                _allowTextureChange = true;
            }
            if ((DamageAlphaTexturePath == null) || (DamageAlphaTexturePath == ""))
            {
                _allowAlphaChange = false;
            }
            else
            {
                _damageAlphaSpritePath = DamageAlphaTexturePath;
                _allowAlphaChange = true;
            }

            _hasDamageWaiting = false;
            _pendingDamage = new List<Vector2>();

            _updateCurrent = 0f;
            _updateTime = UpdateSeconds;
            this.Active = true;
        }

        #endregion

        #region Class functions

        public void Damage(Vector2 DamagePosition)
        {
            _hasDamageWaiting = true;
            _pendingDamage.Add(DamagePosition);
        }

        #endregion

        #region Overridden functions

        protected override void Load()
        {
            //note: B then A just so the code for update reads easier
            if (_allowTextureChange)
            {
                _damageSprite = ParentEngine.Content.Load<Texture2D>(_damageSpritePath);
                _damageSpriteOrigin = new Vector2();
                _damageSpriteOrigin.X = _damageSprite.Width / 2;
                _damageSpriteOrigin.Y = _damageSprite.Height / 2;
                _damageSpriteDataB = new Color[_damageSprite.Width * _damageSprite.Height];
                _damageSprite.GetData<Color>(_damageSpriteDataB);
            }

            if (_allowAlphaChange)
            {
                _damageAlphaSprite = ParentEngine.Content.Load<Texture2D>(_damageAlphaSpritePath);
                _damageAlphaSpriteOrigin = new Vector2();
                _damageAlphaSpriteOrigin.X = _damageAlphaSprite.Width / 2;
                _damageAlphaSpriteOrigin.Y = _damageAlphaSprite.Height / 2;
                _damageSpriteDataA = new Color[_damageAlphaSprite.Width * _damageAlphaSprite.Height];
                _damageAlphaSprite.GetData<Color>(_damageSpriteDataA);
            }

            base.Load();
        }

        public override void Update()
        {
            //TODO: optimise
            if (_updateCurrent >= _updateTime)
            {
                if (_updateTime > 0f)
                {
                    _updateCurrent -= _updateTime;
                }
                else
                {
                    _updateCurrent = 0f;
                }

                if (_hasDamageWaiting)
                {
                    _hasDamageWaiting = false;

                    Texture2D tmpSprite = sprite;
                    Color[] vpc = new Color[tmpSprite.Width * tmpSprite.Height];
                    tmpSprite.GetData<Color>(vpc);

                    for (int dm = _pendingDamage.Count - 1; dm >= 0; dm--)
                    {
                        //apply the new alpha
                        if (_allowAlphaChange)
                        {
                            for (int i = 0; i < _damageAlphaSprite.Width; i++)
                            {
                                for (int j = 0; j < _damageAlphaSprite.Height; j++)
                                {
                                    //red areas get removed, no partial removals.
                                    if (_damageSpriteDataA[i + j * _damageAlphaSprite.Width].R > 200)
                                    {
                                        //make the pixel fully transparent.
                                        int x = (int)(i - _damageAlphaSpriteOrigin.X + _pendingDamage[dm].X),
                                            y = (int)(j - _damageAlphaSpriteOrigin.Y + _pendingDamage[dm].Y);
                                        if ((x >= 0) && (x < sprite.Width) && (y >= 0) && (y < sprite.Height))
                                        {
                                            int r = (int)(x + y * sprite.Width);
                                            if ((r >= 0) && (r < vpc.Length))
                                            {
                                                vpc[r] = Color.Transparent;
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        if (_allowTextureChange)
                        {
                            for (int i = 0; i < _damageSprite.Width; i++)
                            {
                                for (int j = 0; j < _damageSprite.Height; j++)
                                {
                                    //see through areas ignored
                                    if (_damageSpriteDataB[i + j * _damageSprite.Width].A != 0)
                                    {
                                        int x = (int)(i - _damageSpriteOrigin.X + _pendingDamage[dm].X),
                                            y = (int)(j - _damageSpriteOrigin.Y + _pendingDamage[dm].Y);
                                        if ((x >= 0) && (x < sprite.Width) && (y >= 0) && (y < sprite.Height))
                                        {
                                            int r = (int)(x + y * sprite.Width);
                                            if ((r >= 0) && (r < vpc.Length))
                                            {
                                                //see through areas ignored
                                                if (vpc[r].A != 0)
                                                {
                                                    vpc[r].R = _damageSpriteDataB[i + j * _damageSprite.Width].R;
                                                    vpc[r].G = _damageSpriteDataB[i + j * _damageSprite.Width].G;
                                                    vpc[r].B = _damageSpriteDataB[i + j * _damageSprite.Width].B;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }

                        _pendingDamage.RemoveAt(dm);
                    }

                    tmpSprite.SetData<Color>(vpc);
                }
            }
            _updateCurrent += 1;//ParentEngine.GameTime.ElapsedGameTime.Milliseconds / 1000;

            base.Update();
        }
        
        #endregion
    }
}
